const Pending = 'pending'
const Fulfilled = 'fulfilled'
const Rejected = 'rejected'

class mypromise {
    constructor(executor){
        try {
            executor(this.resolve, this.reject);
        } catch (e) {
            this.reject(e);
        }
    }
    status = Pending;
    value = undefined;
    reason = undefined;
    //失败/成功状态
    successcallback = [];
    failcallback = [];
    resolve = value => {
        if (this.status !== Pending) return
        this.status = Fulfilled;
        // 保存成功之后的值
        this.value = value;
        // 判断回调是否存在
        this.successcallback && this.successcallback();
        while (this.successcallback.length) this.successcallback.shift()()
    }
    reject = reason => {
        if (this.status !== Pending) return
        this.status = Rejected;
        //保存失败之后的值
        this.reason = reason;
        this.failcallback && this.failcallback();
        while (this.failcallback.length) this.failcallback.shift()()
    }
   // 同一个promise下面的then可以被多次调用

    then (succCallback, failCallback) {
        succCallback = succCallback ? succCallback : value => value; // 没有参数时候什么也不执行继续向下传递
        failCallback = failCallback ? failCallback : reason => {
            throw reason;
        };
        let promise2 = new mypromise((resolve, reject) => {
            if (this.status == Fulfilled) {
                setTimeout(() => { // 为了获取promise2，在此改为异步代码
                    try { // 失败的情况下仍然能够进行下去，可以在下一个里面接受返回值
                        let val = succCallback(this.value);
                        // 将上一个then方法的返回结果传递给下一个promise 判断是普通值还是promise对象
                        resolvepromise(promise2, val, resolve, reject);
                    } catch (e) {
                        // 此处有错但是需要到下一个then的rejece里面被抛出
                        reject(e);
                    }
                }, 0)
            } else if (this.status == Rejected) {
                setTimeout(() => { // 为了获取promise2，在此改为异步代码
                    try { // 失败的情况下仍然能够进行下去，可以在下一个里面接受返回值
                        let val = failCallback(this.reason);
                        // 将上一个then方法的返回结果传递给下一个promise 判断是普通值还是promise对象
                        resolvepromise(promise2, val, resolve, reject);
                    } catch (e) {
                        // 此处有错但是需要到下一个then的rejece里面被抛出
                        reject(e);
                    }
                }, 0)
            } else {
                //等待状态
                // 存储回调方法
                //异步时候可能有多个回调方法用数组存储
                this.successcallback = successcallback.push(() => {
                    setTimeout(() => { // 为了获取promise2，在此改为异步代码
                        try { // 失败的情况下仍然能够进行下去，可以在下一个里面接受返回值
                            let val = succCallback(this.value);
                            // 将上一个then方法的返回结果传递给下一个promise 判断是普通值还是promise对象
                            resolvepromise(promise2, val, resolve, reject);
                        } catch (e) {
                            // 此处有错但是需要到下一个then的rejece里面被抛出
                            reject(e);
                        }
                    }, 0)
                });
                this.failcallback = failcallback.push(() => {
                    setTimeout(() => { // 为了获取promise2，在此改为异步代码
                        try { // 失败的情况下仍然能够进行下去，可以在下一个里面接受返回值
                            let val = failCallback(this.reason);
                            // 将上一个then方法的返回结果传递给下一个promise 判断是普通值还是promise对象
                            resolvepromise(promise2, val, resolve, reject);
                        } catch (e) {
                            // 此处有错但是需要到下一个then的rejece里面被抛出
                            reject(e);
                        }
                    }, 0)
                });
            }
        });
        return promise2;
    }
    // all 方法允许所有的方法异步执行，返回值是promise对象，会等所有的东西返回之后再结束，一失败全失败, 解决异步并发问题
    static all (arr) {
        let resulet= [];
        let index = 0;
        return new mypromise((resolve, reject) => {
            function adddata (key, value) {
                resulet[key] = value;
                index ++;
                if (index == arr.length) {
                    resolve(value)
                }
            }
            for (let i = 0; i < arr.length; i++) {
                let current = resulet[i];
                if (current instanceof mypromise) {
                    current.then(value => adddata(i, value), reason => reject(reason))
                } else {
                    // 普通值
                    adddata(i, arr[i]);
                }
            }
        });
    }

    // 将给定的值转为promise对象
    static resolve (value) {
        if (value instanceof mypromise) return value
        return new mypromise(resolve => resolve(value));
    }
    // finally 无论最终的状态是成功还是失败都会把所有的方法执行 finally之后仍然可以then链式调用
    finally (callback) {
        this.then(value => {
            return mypromise.resolve(callback()).then(() => value);
            return value;
        }, reason => {
            return mypromise.resolve(callback()).then(() => {throw reason}); // 此处抛出的reason是该方法内的reason
            throw reason;
        })
    }
    // catch 方法 处理当前promise的对象结果为失败的状态
    catch (failcallback) {
        return this.then(undefined, failcallback)
    }
}

function resolvepromise (promise2, v, resolve, reject) {
    if (promise2 === v) {
        reject(new TypeError('promise发生了循环调用'));
    }
    if (v instanceof mypromise) {
        v.then(resolve, reject)
    } else {
        resolve(v);
    }
}

module.exports = mypromise;
